﻿/* 
* Copyright (c) 2010, The University of Texas at Austin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, 
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, 
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, 
* this list of conditions and the following disclaimer in the documentation and/or other materials 
* provided with the distribution.
*
* Neither the name of The University of Texas at Austin nor the names of its contributors may be 
* used to endorse or promote products derived from this software without specific prior written 
* permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Bio.Data.Interfaces;
using Bio.Views.Structure.Editor.Internal.Editing;
using Bio.Views.Structure.Editor.Internal.Rendering;
using Bio.Views.Structure.Editor.Views;
using JulMar.Windows.Interfaces;
using JulMar.Windows.Mvvm;

namespace Bio.Views.Structure.Editor.ViewModels
{
    public class ConfigureStructureElementVisualPropertiesViewModel : ViewModel
    {
        public ObservableCollection<string> GlobalProperties { get; private set; }
        public ObservableCollection<string> TextProperties { get; private set; }
        public ObservableCollection<string> CircleProperties { get; private set; }
        public ObservableCollection<string> BasePairConnectorProperties { get; private set; }

        private bool _editNucleotideRenderingStyle;
        [EditablePropertyFlag("NucleotideRenderingStyle")]
        public bool EditNucleotideRenderingStyle
        {
            get { return _editNucleotideRenderingStyle; }
            set
            {
                _editNucleotideRenderingStyle = value;
                if (!_editNucleotideRenderingStyle)
                {
                    if (_changes.HasNucleotideRenderingStyleChange)
                        _changes.ClearNucleotideRenderingStyleChange();

                    if (_editedGlobalProperties.Contains("NucleotideRenderingStyle"))
                    {
                        _editedGlobalProperties.Remove("NucleotideRenderingStyle");
                        GlobalProperties.Add("NucleotideRenderingStyle");
                    }
                }
                else
                {
                    if (!_editedTextProperties.Contains("NucleotideRenderingStyle"))
                    {
                        TextProperties.Remove("NucleotideRenderingStyle");
                        _editedTextProperties.Add("NucleotideRenderingStyle");
                    }
                }
                OnPropertyChanged("EditNucleotideRenderingStyle", "NucleotideRenderingStyle");
            }
        }

        [EditableProperty("Global")]
        public NucleotideRenderingMode? NucleotideRenderingStyle
        {
            get { return _changes.NucleotideRenderingStyleChange; }
            set
            {
                _changes.MarkNucleotideRenderingStyleChange(value);
                OnPropertyChanged("NucleotideRenderingStyle");
            }
        }

        private string _selectedGlobalProperty;
        public string SelectedGlobalProperty
        {
            get { return _selectedGlobalProperty; }
            set
            {
                _selectedGlobalProperty = value;
                OnPropertyChanged("SelectedGlobalProperty");
            }
        }

        private bool _editNucleotideFontFamily;
        [EditablePropertyFlag("NucleotideFontFamily")]
        public bool EditNucleotideFontFamily
        {
            get { return _editNucleotideFontFamily; }
            set
            {
                _editNucleotideFontFamily = value;
                if (!_editNucleotideFontFamily)
                {
                    if (_changes.HasNucleotideFontFamilyChange)
                        _changes.ClearNucleotideFontFamilyChange();

                    if (_editedTextProperties.Contains("NucleotideFontFamily"))
                    {
                        _editedTextProperties.Remove("NucleotideFontFamily");
                        TextProperties.Add("NucleotideFontFamily");
                    }
                }
                else
                {
                    if (!_editedTextProperties.Contains("NucleotideFontFamily"))
                    {
                        TextProperties.Remove("NucleotideFontFamily");
                        _editedTextProperties.Add("NucleotideFontFamily");
                    }
                }
                OnPropertyChanged("EditNucleotideFontFamily", "NucleotideFontFamily");
            }
        }

        [EditableProperty("Text")]
        public FontFamily NucleotideFontFamily
        {
            get { return _changes.NucleotideFontFamilyChange; }
            set
            {
                _changes.MarkNucleotideFontFamilyChange(value);
                OnPropertyChanged("NucleotideFontFamily");
            }
        }

        private bool _editNucleotideFontStyle;
        [EditablePropertyFlag("NucleotideFontStyle")]
        public bool EditNucleotideFontStyle
        {
            get { return _editNucleotideFontStyle; }
            set
            {
                _editNucleotideFontStyle = value;
                if (!_editNucleotideFontStyle)
                {
                    if (_changes.HasNucleotideFontStyleChange)
                        _changes.ClearNucleotideFontStyleChange();

                    if (_editedTextProperties.Contains("NucleotideFontStyle"))
                    {
                        _editedTextProperties.Remove("NucleotideFontStyle");
                        TextProperties.Add("NucleotideFontStyle");
                    }
                }
                else
                {
                    if (!_editedTextProperties.Contains("NucleotideFontStyle"))
                    {
                        TextProperties.Remove("NucleotideFontStyle");
                        _editedTextProperties.Add("NucleotideFontStyle");
                    }
                }
                OnPropertyChanged("EditNucleotideFontStyle", "NucleotideFontStyle");
            }
        }

        [EditableProperty("Text")]
        public FontStyle? NucleotideFontStyle
        {
            get { return _changes.NucleotideFontStyleChange; }
            set
            {
                _changes.MarkNucleotideFontStyleChange(value);
                OnPropertyChanged("NucleotideFontStyle");
            }
        }

        private bool _editNucleotideFontWeight;
        [EditablePropertyFlag("NucleotideFontWeight")]
        public bool EditNucleotideFontWeight
        {
            get { return _editNucleotideFontWeight; }
            set
            {
                _editNucleotideFontWeight = value;
                if (!_editNucleotideFontWeight)
                {
                    if (_changes.HasNucleotideFontWeightChange)
                        _changes.ClearNucleotideFontWeightChange();

                    if (_editedTextProperties.Contains("NucleotideFontWeight"))
                    {
                        _editedTextProperties.Remove("NucleotideFontWeight");
                        TextProperties.Add("NucleotideFontWeight");
                    }
                }
                else
                {
                    if (!_editedTextProperties.Contains("NucleotideFontWeight"))
                    {
                        TextProperties.Remove("NucleotideFontWeight");
                        _editedTextProperties.Add("NucleotideFontWeight");
                    }
                }
                OnPropertyChanged("EditNucleotideFontWeight", "NucleotideFontWeight");
            }
        }

        [EditableProperty("Text")]
        public FontWeight? NucleotideFontWeight
        {
            get { return _changes.NucleotideFontWeightChange; }
            set
            {
                _changes.MarkNucleotideFontWeightChange(value);
                OnPropertyChanged("NucleotideFontWeight");
            }
        }

        private bool _editNucleotideFontSize;
        [EditablePropertyFlag("NucleotideFontSize")]
        public bool EditNucleotideFontSize
        {
            get { return _editNucleotideFontSize; }
            set
            {
                _editNucleotideFontSize = value;
                if (!_editNucleotideFontSize)
                {
                    if (_changes.HasNucleotideFontSizeChange)
                        _changes.ClearNucleotideFontSizeChange();

                    if (_editedTextProperties.Contains("NucleotideFontSize"))
                    {
                        _editedTextProperties.Remove("NucleotideFontSize");
                        TextProperties.Add("NucleotideFontSize");
                    }
                }
                else
                {
                    if (!_editedTextProperties.Contains("NucleotideFontSize"))
                    {
                        TextProperties.Remove("NucleotideFontSize");
                        _editedTextProperties.Add("NucleotideFontSize");
                    }
                }
                OnPropertyChanged("EditNucleotideFontSize", "NucleotideFontSize");
            }
        }

        [EditableProperty("Text")]
        public double? NucleotideFontSize
        {
            get { return _changes.NucleotideFontSizeChange; }
            set
            {
                _changes.MarkNucleotideFontSizeChange(value);
                OnPropertyChanged("NucleotideFontSize");
            }
        }

        private bool _editNucleotideFill;
        [EditablePropertyFlag("NucleotideFill")]
        public bool EditNucleotideFill
        {
            get { return _editNucleotideFill; }
            set
            {
                _editNucleotideFill = value;
                if (!_editNucleotideFill)
                {
                    if (_changes.HasNucleotideFillChange)
                        _changes.ClearNucleotideFillChange();

                    if (_editedTextProperties.Contains("NucleotideFill"))
                    {
                        _editedTextProperties.Remove("NucleotideFill");
                        TextProperties.Add("NucleotideFill");
                    }
                }
                else
                {
                    if (!_editedTextProperties.Contains("NucleotideFill"))
                    {
                        TextProperties.Remove("NucleotideFill");
                        _editedTextProperties.Add("NucleotideFill");
                    }
                }
                OnPropertyChanged("EditNucleotideFill", "NucleotideFill");
            }
        }

        [EditableProperty("Text")]
        public Brush NucleotideFill
        {
            get { return _changes.NucleotideFillChange; }
            set
            {
                _changes.MarkNucleotideFillChange(value);
                OnPropertyChanged("NucleotideFill");
            }
        }

        /*[EditableProperty("Text")]
        public bool? IsNucleotideSubstituted
        {
            get { return _changes.IsNucleotideSubstitutedChange; }
            set
            {
                _changes.MarkIsNucleotideSubstitutedChange(value);
                OnPropertyChanged("IsNucleotideSubstituted");
            }
        }

        [EditableProperty("Text")]
        public char? NucleotideSubstitution
        {
            get { return _changes.NucleotideSubstitutionChange; }
            set
            {
                _changes.MarkNucleotideSubstitutionChange(value);
                OnPropertyChanged("NucleotideSubstitution");
            }
        }*/

        private string _selectedTextProperty;
        public string SelectedTextProperty
        {
            get { return _selectedTextProperty; }
            set
            {
                _selectedTextProperty = value;
                OnPropertyChanged("SelectedTextProperty");
            }
        }

        private bool _editNucleotideCircleDiameter;
        [EditablePropertyFlag("NucleotideCircleDiameter")]
        public bool EditNucleotideCircleDiameter
        {
            get { return _editNucleotideCircleDiameter; }
            set
            {
                _editNucleotideCircleDiameter = value;
                if (!_editNucleotideCircleDiameter)
                {
                    if (_changes.HasNucleotideCircleDiameterChange)
                        _changes.ClearNucleotideCircleDiameterChange();

                    if (_editedCircleProperties.Contains("NucleotideCircleDiameter"))
                    {
                        _editedCircleProperties.Remove("NucleotideCircleDiameter");
                        CircleProperties.Add("NucleotideCircleDiameter");
                    }
                }
                else
                {
                    if (!_editedCircleProperties.Contains("NucleotideCircleDiameter"))
                    {
                        CircleProperties.Remove("NucleotideCircleDiameter");
                        _editedCircleProperties.Add("NucleotideCircleDiameter");
                    }
                }
                OnPropertyChanged("EditNucleotideCircleDiameter", "NucleotideCircleDiameter");
            }
        }

        [EditableProperty("Circle")]
        public double? NucleotideCircleDiameter
        {
            get { return _changes.NucleotideCircleDiameterChange; }
            set
            {
                _changes.MarkNucleotideCircleDiameterChange(value);
                OnPropertyChanged("NucleotideCircleDiameter");
            }
        }

        private bool _editNucleotideCircleEdgeThickness;
        [EditablePropertyFlag("NucleotideCircleEdgeThickness")]
        public bool EditNucleotideCircleEdgeThickness
        {
            get { return _editNucleotideCircleEdgeThickness; }
            set
            {
                _editNucleotideCircleEdgeThickness = value;
                if (!_editNucleotideCircleEdgeThickness)
                {
                    if (_changes.HasNucleotideCircleEdgeThicknessChange)
                        _changes.ClearNucleotideCircleEdgeThicknessChange();

                    if (_editedCircleProperties.Contains("NucleotideCircleEdgeThickness"))
                    {
                        _editedCircleProperties.Remove("NucleotideCircleEdgeThickness");
                        CircleProperties.Add("NucleotideCircleEdgeThickness");
                    }
                }
                else
                {
                    if (!_editedCircleProperties.Contains("NucleotideCircleEdgeThickness"))
                    {
                        CircleProperties.Remove("NucleotideCircleEdgeThickness");
                        _editedCircleProperties.Add("NucleotideCircleEdgeThickness");
                    }
                }
                OnPropertyChanged("EditNucleotideCircleEdgeThickness", "NucleotideCircleEdgeThickness");
            }
        }

        [EditableProperty("Circle")]
        public double? NucleotideCircleEdgeThickness
        {
            get { return _changes.NucleotideCircleEdgeThicknessChange; }
            set
            {
                _changes.MarkNucleotideCircleEdgeThicknessChange(value);
                OnPropertyChanged("NucleotideCircleEdgeThickness");
            }
        }

        private bool _editNucleotideCircleIsFilled;
        [EditablePropertyFlag("NucleotideCircleIsFilled")]
        public bool EditNucleotideCircleIsFilled
        {
            get { return _editNucleotideCircleIsFilled; }
            set
            {
                _editNucleotideCircleIsFilled = value;
                if (!_editNucleotideCircleIsFilled)
                {
                    if (_changes.HasNucleotideCircleIsFilledChange)
                        _changes.ClearNucleotideCircleIsFilledChange();

                    if (_editedCircleProperties.Contains("NucleotideCircleIsFilled"))
                    {
                        _editedCircleProperties.Remove("NucleotideCircleIsFilled");
                        CircleProperties.Add("NucleotideCircleIsFilled");
                    }
                }
                else
                {
                    if (!_editedCircleProperties.Contains("NucleotideCircleIsFilled"))
                    {
                        CircleProperties.Remove("NucleotideCircleIsFilled");
                        _editedCircleProperties.Add("NucleotideCircleIsFilled");
                    }
                }
                OnPropertyChanged("EditNucleotideCircleIsFilled", "NucleotideCircleIsFilled");
            }
        }

        [EditableProperty("Circle")]
        public bool? NucleotideCircleIsFilled
        {
            get { return _changes.NucleotideCircleIsFilledChange; }
            set
            {
                _changes.MarkNucleotideCircleIsFilledChange(value);
                OnPropertyChanged("NucleotideCircleIsFilled");
            }
        }

        private bool _editNucleotideCircleFill;
        [EditablePropertyFlag("NucleotideCircleFill")]
        public bool EditNucleotideCircleFill
        {
            get { return _editNucleotideCircleFill; }
            set
            {
                _editNucleotideCircleFill = value;
                if (!_editNucleotideCircleFill)
                {
                    if (_changes.HasNucleotideCircleFillChange)
                        _changes.ClearNucleotideCircleFillChange();

                    if (_editedCircleProperties.Contains("NucleotideCircleFill"))
                    {
                        _editedCircleProperties.Remove("NucleotideCircleFill");
                        CircleProperties.Add("NucleotideCircleFill");
                    }
                }
                else
                {
                    if (!_editedCircleProperties.Contains("NucleotideCircleFill"))
                    {
                        CircleProperties.Remove("NucleotideCircleFill");
                        _editedCircleProperties.Add("NucleotideCircleFill");
                    }
                }
                OnPropertyChanged("EditNucleotideCircleFill", "NucleotideCircleFill");
            }
        }

        [EditableProperty("Circle")]
        public Brush NucleotideCircleFill
        {
            get { return _changes.NucleotideCircleFillChange; }
            set
            {
                _changes.MarkNucleotideCircleFillChange(value);
                OnPropertyChanged("NucleotideCircleFill");
            }
        }

        private bool _editNucleotideCircleStroke;
        [EditablePropertyFlag("NucleotideCircleStroke")]
        public bool EditNucleotideCircleStroke
        {
            get { return _editNucleotideCircleStroke; }
            set
            {
                _editNucleotideCircleStroke = value;
                if (!_editNucleotideCircleStroke)
                {
                    if (_changes.HasNucleotideCircleStrokeChange)
                        _changes.ClearNucleotideCircleStrokeChange();

                    if (_editedCircleProperties.Contains("NucleotideCircleStroke"))
                    {
                        _editedCircleProperties.Remove("NucleotideCircleStroke");
                        CircleProperties.Add("NucleotideCircleStroke");
                    }
                }
                else
                {
                    if (!_editedCircleProperties.Contains("NucleotideCircleStroke"))
                    {
                        CircleProperties.Remove("NucleotideCircleStroke");
                        _editedCircleProperties.Add("NucleotideCircleStroke");
                    }
                }
                OnPropertyChanged("EditNucleotideCircleStroke", "NucleotideCircleStroke");
            }
        }

        [EditableProperty("Circle")]
        public Brush NucleotideCircleStroke
        {
            get { return _changes.NucleotideCircleStrokeChange; }
            set
            {
                _changes.MarkNucleotideCircleStrokeChange(value);
                OnPropertyChanged("NucleotideCircleStroke");
            }
        }

        private string _selectedCircleProperty;
        public string SelectedCircleProperty
        {
            get { return _selectedCircleProperty; }
            set
            {
                _selectedCircleProperty = value;
                OnPropertyChanged("SelectedCircleProperty");
            }
        }

        private bool _editBasePairConnectorIsFilled;
        [EditablePropertyFlag("BasePairConnectorIsFilled")]
        public bool EditBasePairConnectorIsFilled
        {
            get { return _editBasePairConnectorIsFilled; }
            set
            {
                _editBasePairConnectorIsFilled = value;
                if (!_editBasePairConnectorIsFilled)
                {
                    if (_changes.HasBasePairConnectorIsFilledChange)
                        _changes.ClearBasePairConnectorIsFilledChange();

                    if (_editedBPConnectorProperties.Contains("BasePairConnectorIsFilled"))
                    {
                        BasePairConnectorProperties.Add("BasePairConnectorIsFilled");
                        _editedBPConnectorProperties.Remove("BasePairConnectorIsFilled");
                    }
                }
                else
                {
                    if (!_editedBPConnectorProperties.Contains("BasePairConnectorIsFilled"))
                    {
                        BasePairConnectorProperties.Remove("BasePairConnectorIsFilled");
                        _editedBPConnectorProperties.Add("BasePairConnectorIsFilled");
                    }
                }
                OnPropertyChanged("EditBasePairConnectorIsFilled", "BasePairConnectorIsFilled");
            }
        }

        [EditableProperty("Connector")]
        public bool? BasePairConnectorIsFilled
        {
            get { return _changes.BasePairConnectorIsFilledChange; }
            set
            {
                _changes.MarkBasePairConnectorIsFilledChange(value);
                OnPropertyChanged("BasePairConnectorIsFilled");
            }
        }

        private bool _editBasePairConnectorIsVisible;
        [EditablePropertyFlag("BasePairConnectorIsVisible")]
        public bool EditBasePairConnectorIsVisible
        {
            get { return _editBasePairConnectorIsVisible; }
            set
            {
                _editBasePairConnectorIsVisible = value;
                if (!_editBasePairConnectorIsVisible)
                {
                    if (_changes.HasBasePairConnectorIsVisibleChange)
                        _changes.ClearBasePairConnectorIsVisibleChange();

                    if (_editedBPConnectorProperties.Contains("BasePairConnectorIsVisible"))
                    {
                        BasePairConnectorProperties.Add("BasePairConnectorIsVisible");
                        _editedBPConnectorProperties.Remove("BasePairConnectorIsVisible");
                    }
                }
                else
                {
                    if (!_editedBPConnectorProperties.Contains("BasePairConnectorIsVisible"))
                    {
                        BasePairConnectorProperties.Remove("BasePairConnectorIsVisible");
                        _editedBPConnectorProperties.Add("BasePairConnectorIsVisible");
                    }
                }
                OnPropertyChanged("EditBasePairConnectorIsVisible", "BasePairConnectorIsVisible");
            }
        }

        [EditableProperty("Connector")]
        public bool? BasePairConnectorIsVisible
        {
            get { return _changes.BasePairConnectorIsVisibleChange; }
            set
            {
                _changes.MarkBasePairConnectorIsVisibleChange(value);
                OnPropertyChanged("BasePairConnectorIsVisible");
            }
        }

        private bool _editBasePairConnectorFill;
        [EditablePropertyFlag("BasePairConnectorFill")]
        public bool EditBasePairConnectorFill
        {
            get { return _editBasePairConnectorFill; }
            set
            {
                _editBasePairConnectorFill = value;
                if (!_editBasePairConnectorFill)
                {
                    if (_changes.HasBasePairConnectorFillChange)
                        _changes.ClearBasePairConnectorFillChange();

                    if (_editedBPConnectorProperties.Contains("BasePairConnectorFill"))
                    {
                        BasePairConnectorProperties.Add("BasePairConnectorFill");
                        _editedBPConnectorProperties.Remove("BasePairConnectorFill");
                    }
                }
                else
                {
                    if (!_editedBPConnectorProperties.Contains("BasePairConnectorFill"))
                    {
                        BasePairConnectorProperties.Remove("BasePairConnectorFill");
                        _editedBPConnectorProperties.Add("BasePairConnectorFill");
                    }
                }
                OnPropertyChanged("EditBasePairConnectorFill", "BasePairConnectorFill");
            }
        }

        [EditableProperty("Connector")]
        public Brush BasePairConnectorFill
        {
            get { return _changes.BasePairConnectorFillChange; }
            set
            {
                _changes.MarkBasePairConnectorFillChange(value);
                OnPropertyChanged("BasePairConnectorFill");
            }
        }

        private bool _editBasePairConnectorStroke;
        [EditablePropertyFlag("BasePairConnectorStroke")]
        public bool EditBasePairConnectorStroke
        {
            get { return _editBasePairConnectorStroke; }
            set
            {
                _editBasePairConnectorStroke = value;
                if (!_editBasePairConnectorStroke)
                {
                    if (_changes.HasBasePairConnectorStrokeChange)
                        _changes.ClearBasePairConnectorStrokeChange();

                    if (_editedBPConnectorProperties.Contains("BasePairConnectorStroke"))
                    {
                        BasePairConnectorProperties.Add("BasePairConnectorStroke");
                        _editedBPConnectorProperties.Remove("BasePairConnectorStroke");
                    }
                }
                else
                {
                    if (!_editedBPConnectorProperties.Contains("BasePairConnectorStroke"))
                    {
                        BasePairConnectorProperties.Remove("BasePairConnectorStroke");
                        _editedBPConnectorProperties.Add("BasePairConnectorStroke");
                    }
                }
                OnPropertyChanged("EditBasePairConnectorStroke", "BasePairConnectorStroke");
            }
        }

        [EditableProperty("Connector")]
        public Brush BasePairConnectorStroke
        {
            get { return _changes.BasePairConnectorStrokeChange; }
            set
            {
                _changes.MarkBasePairConnectorStrokeChange(value);
                OnPropertyChanged("BasePairConnectorStroke");
            }
        }

        private bool _editBasePairConnectorSize;
        [EditablePropertyFlag("BasePairConnectorSize")]
        public bool EditBasePairConnectorSize
        {
            get { return _editBasePairConnectorSize; }
            set
            {
                _editBasePairConnectorSize = value;
                if (!_editBasePairConnectorSize)
                {
                    if (_changes.HasBasePairConnectorSizeChange)
                        _changes.ClearBasePairConnectorSizeChange();

                    if (_editedBPConnectorProperties.Contains("BasePairConnectorSize"))
                    {
                        BasePairConnectorProperties.Add("BasePairConnectorSize");
                        _editedBPConnectorProperties.Remove("BasePairConnectorSize");
                    }
                }
                else
                {
                    if (!_editedBPConnectorProperties.Contains("BasePairConnectorSize"))
                    {
                        BasePairConnectorProperties.Remove("BasePairConnectorSize");
                        _editedBPConnectorProperties.Add("BasePairConnectorSize");
                    }
                }
                OnPropertyChanged("EditBasePairConnectorSize", "BasePairConnectorSize");
            }
        }

        [EditableProperty("Connector")]
        public double? BasePairConnectorSize
        {
            get { return _changes.BasePairConnectorSizeChange; }
            set
            {
                _changes.MarkBasePairConnectorSizeChange(value);
                OnPropertyChanged("BasePairConnectorSize");
            }
        }

        private bool _editBasePairConnectorStrokeThickness;
        [EditablePropertyFlag("BasePairConnectorStrokeThickness")]
        public bool EditBasePairConnectorStrokeThickness
        {
            get { return _editBasePairConnectorStrokeThickness; }
            set
            {
                _editBasePairConnectorStrokeThickness = value;
                if (!_editBasePairConnectorStrokeThickness)
                {
                    if (_changes.HasBasePairConnectorStrokeThicknessChange)
                        _changes.ClearBasePairConnectorStrokeThicknessChange();

                    if (_editedBPConnectorProperties.Contains("BasePairConnectorStrokeThickness"))
                    {
                        BasePairConnectorProperties.Add("BasePairConnectorStrokeThickness");
                        _editedBPConnectorProperties.Remove("BasePairConnectorStrokeThickness");
                    }
                }
                else
                {
                    if (!_editedBPConnectorProperties.Contains("BasePairConnectorStrokeThickness"))
                    {
                        BasePairConnectorProperties.Remove("BasePairConnectorStrokeThickness");
                        _editedBPConnectorProperties.Add("BasePairConnectorStrokeThickness");
                    }
                }
                OnPropertyChanged("EditBasePairConnectorStrokeThickness", "BasePairConnectorStrokeThickness");
            }
        }

        [EditableProperty("Connector")]
        public double? BasePairConnectorStrokeThickness
        {
            get { return _changes.BasePairConnectorStrokeThicknessChange; }
            set
            {
                _changes.MarkBasePairConnectorStrokeThicknessChange(value);
                OnPropertyChanged("BasePairConnectorStrokeThickness");
            }
        }

        private bool _editBasePairConnectorRenderingStyle;
        [EditablePropertyFlag("BasePairConnectorRenderingStyle")]
        public bool EditBasePairConnectorRenderingStyle
        {
            get { return _editBasePairConnectorRenderingStyle; }
            set
            {
                _editBasePairConnectorRenderingStyle = value;
                if (!_editBasePairConnectorRenderingStyle)
                {
                    if (_changes.HasBasePairConnectorRenderingStyleChange)
                        _changes.ClearBasePairConnectorRenderingStyleChange();

                    if (_editedBPConnectorProperties.Contains("BasePairConnectorRenderingStyle"))
                    {
                        BasePairConnectorProperties.Add("BasePairConnectorRenderingStyle");
                        _editedBPConnectorProperties.Remove("BasePairConnectorRenderingStyle");
                    }
                }
                else
                {
                    if (!_editedBPConnectorProperties.Contains("BasePairConnectorRenderingStyle"))
                    {
                        BasePairConnectorProperties.Remove("BasePairConnectorRenderingStyle");
                        _editedBPConnectorProperties.Add("BasePairConnectorRenderingStyle");
                    }
                }
                OnPropertyChanged("EditBasePairConnectorRenderingStyle", "BasePairConnectorRenderingStyle");
            }
        }

        [EditableProperty("Connector")]
        public BasePairConnectorRenderingMode? BasePairConnectorRenderingStyle
        {
            get { return _changes.BasePairConnectorRenderingStyleChange; }
            set
            {
                _changes.MarkBasePairConnectorRenderingStyleChange(value);
                OnPropertyChanged("BasePairConnectorRenderingStyle");
            }
        }

        private string _selectedConnectorProperty;
        public string SelectedConnectorProperty
        {
            get { return _selectedConnectorProperty; }
            set
            {
                _selectedConnectorProperty = value;
                OnPropertyChanged("SelectedConnectorProperty");
            }
        }

        private bool _editingNucleotideProperties;
        public bool EditingNucleotideProperties
        {
            get { return _editingNucleotideProperties; }
            set
            {
                _editingNucleotideProperties = value;
                OnPropertyChanged("EditingNucleotideProperties");
            }
        }

        public ICommand AddGlobalPropertyEditCommand { get; private set; }
        public ICommand ResetGlobalPropertyEditsCommand { get; private set; }
        public ICommand AddTextPropertyEditCommand { get; private set; }
        public ICommand AddAllTextPropertyEditsCommand { get; private set; }
        public ICommand ClearAllTextPropertyEditsCommand { get; private set; }
        public ICommand PromptForNucleotideFillBrushCommand { get; private set; }
        public ICommand AddCirclePropertyEditCommand { get; private set; }
        public ICommand AddAllCirclePropertyEditsCommand { get; private set; }
        public ICommand ClearAllCirclePropertyEditsCommand { get; private set; }
        public ICommand PromptForNucleotideCircleFillBrushCommand { get; private set; }
        public ICommand PromptForNucleotideCircleStrokeBrushCommand { get; private set; }
        public ICommand AddConnectorPropertyEditCommand { get; private set; }
        public ICommand AddAllConnectorPropertyEditsCommand { get; private set; }
        public ICommand ClearAllConnectorPropertyEditsCommand { get; private set; }
        public ICommand PromptForConnectorFillBrushCommand { get; private set; }
        public ICommand PromptForConnectorStrokeBrushCommand { get; private set; }
        public ICommand AddFilterConditionCommand { get; private set; }

        public StructureElementPropertyChangeSet Changes
        {
            get { return _changes; }
        }

        public bool ShowCreateFilter
        {
            get { return _showCreateFilter; }
            set
            {
                _showCreateFilter = value;
                OnPropertyChanged("ShowCreateFilter");
            }
        }

        public List<IBioSymbol> NucleotideFilter
        {
            get { return _ntFilter; }
        }

        public List<string> BasePairFilter
        {
            get { return _bpFilter; }
        }

        public ConfigureStructureElementVisualPropertiesViewModel(bool editingNucleotideProperties)
        {
            COLOR_CONVERTER = new ColorConverter();
            EditingNucleotideProperties = editingNucleotideProperties;
            _changes = new StructureElementPropertyChangeSet(true);
            
            AddGlobalPropertyEditCommand = new DelegatingCommand(OnAddGlobalPropertyEdit);
            AddTextPropertyEditCommand = new DelegatingCommand(OnAddTextPropertyEdit);
            PromptForNucleotideFillBrushCommand = new DelegatingCommand(OnPromptForNucleotideFillBrush);
            AddAllTextPropertyEditsCommand = new DelegatingCommand(OnAddAllTextPropertyEdits);
            ClearAllTextPropertyEditsCommand = new DelegatingCommand(OnClearAllTextPropertyEdits);
            AddCirclePropertyEditCommand = new DelegatingCommand(OnAddCirclePropertyEdit);
            AddAllCirclePropertyEditsCommand = new DelegatingCommand(OnAddAllCirclePropertyEdits);
            ClearAllCirclePropertyEditsCommand = new DelegatingCommand(OnClearAllCirclePropertyEdits);
            PromptForNucleotideCircleFillBrushCommand = new DelegatingCommand(OnPromptForNucleotideCircleFillBrush);
            PromptForNucleotideCircleStrokeBrushCommand = new DelegatingCommand(OnPromptForNucleotideCircleStrokeBrush);
            AddConnectorPropertyEditCommand = new DelegatingCommand(OnAddConnectorPropertyEdit);
            AddAllConnectorPropertyEditsCommand = new DelegatingCommand(OnAddAllConnectorPropertyEdits);
            ClearAllConnectorPropertyEditsCommand = new DelegatingCommand(OnClearAllConnectorPropertyEdits);
            PromptForConnectorFillBrushCommand = new DelegatingCommand(OnPromptForConnectorFillBrush);
            PromptForConnectorStrokeBrushCommand = new DelegatingCommand(OnPromptForConnectorStrokeBrush);
            AddFilterConditionCommand = new DelegatingCommand(OnAddFilterCondition);

            GlobalProperties = new ObservableCollection<string>();
            TextProperties = new ObservableCollection<string>();
            CircleProperties = new ObservableCollection<string>();
            BasePairConnectorProperties = new ObservableCollection<string>();

            _editedGlobalProperties = new List<string>();
            _editedTextProperties = new List<string>();
            _editedCircleProperties = new List<string>();
            _editedBPConnectorProperties = new List<string>();
            _ntFilter = new List<IBioSymbol>();
            _bpFilter = new List<string>();

            PropertyInfo[] properties = GetType().GetProperties();
            foreach (var info in properties)
            {
                object[] attr = info.GetCustomAttributes(typeof(EditablePropertyAttribute), false);
                if (attr != null && attr.Length >= 1)
                {
                    EditablePropertyAttribute flagName = attr[0] as EditablePropertyAttribute;
                    if (flagName != null)
                    {
                        if (flagName.Category.Equals("Global"))
                            GlobalProperties.Add(info.Name);
                        else if (flagName.Category.Equals("Text"))
                            TextProperties.Add(info.Name);
                        else if (flagName.Category.Equals("Circle"))
                            CircleProperties.Add(info.Name);
                        else if (flagName.Category.Equals("Connector"))
                            BasePairConnectorProperties.Add(info.Name);
                    }
                }
            }
        }

        private void OnAddGlobalPropertyEdit()
        {
            if (!string.IsNullOrEmpty(SelectedGlobalProperty))
            {
                string selectedGlobalPropertyName = SelectedGlobalProperty;
                //We need to find the flag
                PropertyInfo[] properties = GetType().GetProperties();
                foreach (var info in properties)
                {
                    object[] attr = info.GetCustomAttributes(typeof(EditablePropertyFlagAttribute), false);
                    if (attr != null && attr.Length >= 1)
                    {
                        EditablePropertyFlagAttribute flagName = attr[0] as EditablePropertyFlagAttribute;
                        if (flagName != null)
                        {
                            if (flagName.EditablePropertyName.Equals(selectedGlobalPropertyName))
                            {
                                info.SetValue(this, true, null);
                                break;
                            }
                        }
                    }
                }
            }
        }

        private void OnAddTextPropertyEdit()
        {
            if (!string.IsNullOrEmpty(SelectedTextProperty))
            {
                string selectedTextPropertyName = SelectedTextProperty;
                //We need to find the flag
                PropertyInfo[] properties = GetType().GetProperties();
                foreach (var info in properties)
                {
                    object[] attr = info.GetCustomAttributes(typeof(EditablePropertyFlagAttribute), false);
                    if (attr != null && attr.Length >= 1)
                    {
                        EditablePropertyFlagAttribute flagName = attr[0] as EditablePropertyFlagAttribute;
                        if (flagName != null)
                        {
                            if (flagName.EditablePropertyName.Equals(selectedTextPropertyName))
                            {
                                info.SetValue(this, true, null);
                                break;
                            }
                        }
                    }
                }
            }
        }

        private void OnAddCirclePropertyEdit()
        {
            if (!string.IsNullOrEmpty(SelectedCircleProperty))
            {
                string selectedCirclePropertyName = SelectedCircleProperty;
                //We need to find the flag
                PropertyInfo[] properties = GetType().GetProperties();
                foreach (var info in properties)
                {
                    object[] attr = info.GetCustomAttributes(typeof(EditablePropertyFlagAttribute), false);
                    if (attr != null && attr.Length >= 1)
                    {
                        EditablePropertyFlagAttribute flagName = attr[0] as EditablePropertyFlagAttribute;
                        if (flagName != null)
                        {
                            if (flagName.EditablePropertyName.Equals(selectedCirclePropertyName))
                            {
                                info.SetValue(this, true, null);
                                break;
                            }
                        }
                    }
                }
            }
        }

        private void OnAddConnectorPropertyEdit()
        {
            if (!string.IsNullOrEmpty(SelectedConnectorProperty))
            {
                string selectedConnectorPropertyName = SelectedConnectorProperty;
                //We need to find the flag
                PropertyInfo[] properties = GetType().GetProperties();
                foreach (var info in properties)
                {
                    object[] attr = info.GetCustomAttributes(typeof(EditablePropertyFlagAttribute), false);
                    if (attr != null && attr.Length >= 1)
                    {
                        EditablePropertyFlagAttribute flagName = attr[0] as EditablePropertyFlagAttribute;
                        if (flagName != null)
                        {
                            if (flagName.EditablePropertyName.Equals(selectedConnectorPropertyName))
                            {
                                info.SetValue(this, true, null);
                                break;
                            }
                        }
                    }
                }
            }
        }

        private void OnAddAllTextPropertyEdits()
        {
            if (!EditNucleotideFontFamily) EditNucleotideFontFamily = true;
            if (!EditNucleotideFontStyle) EditNucleotideFontStyle = true;
            if (!EditNucleotideFontWeight) EditNucleotideFontWeight = true;
            if (!EditNucleotideFontSize) EditNucleotideFontSize = true;
            if (!EditNucleotideFill) EditNucleotideFill = true;
        }

        private void OnClearAllTextPropertyEdits()
        {
            if (EditNucleotideFontFamily) EditNucleotideFontFamily = false;
            if (EditNucleotideFontStyle) EditNucleotideFontStyle = false;
            if (EditNucleotideFontWeight) EditNucleotideFontWeight = false;
            if (EditNucleotideFontSize) EditNucleotideFontSize = false;
            if (EditNucleotideFill) EditNucleotideFill = false;
        }

        private void OnAddAllCirclePropertyEdits()
        {
            if (!EditNucleotideCircleDiameter) EditNucleotideCircleDiameter = true;
            if (!EditNucleotideCircleEdgeThickness) EditNucleotideCircleEdgeThickness = true;
            if (!EditNucleotideCircleFill) EditNucleotideCircleFill = true;
            if (!EditNucleotideCircleIsFilled) EditNucleotideCircleIsFilled = true;
            if (!EditNucleotideCircleStroke) EditNucleotideCircleStroke = true;
        }

        private void OnClearAllCirclePropertyEdits()
        {
            if (EditNucleotideCircleDiameter) EditNucleotideCircleDiameter = false;
            if (EditNucleotideCircleEdgeThickness) EditNucleotideCircleEdgeThickness = false;
            if (EditNucleotideCircleFill) EditNucleotideCircleFill = false;
            if (EditNucleotideCircleIsFilled) EditNucleotideCircleIsFilled = false;
            if (EditNucleotideCircleStroke) EditNucleotideCircleStroke = false;
        }

        private void OnAddAllConnectorPropertyEdits()
        {
            if (!EditBasePairConnectorFill) EditBasePairConnectorFill = true;
            if (!EditBasePairConnectorIsFilled) EditBasePairConnectorIsFilled = true;
            if (!EditBasePairConnectorIsVisible) EditBasePairConnectorIsVisible = true;
            if (!EditBasePairConnectorRenderingStyle) EditBasePairConnectorRenderingStyle = true;
            if (!EditBasePairConnectorSize) EditBasePairConnectorSize = true;
            if (!EditBasePairConnectorStroke) EditBasePairConnectorStroke = true;
            if (!EditBasePairConnectorStrokeThickness) EditBasePairConnectorStrokeThickness = true;
        }

        private void OnClearAllConnectorPropertyEdits()
        {
            if (EditBasePairConnectorFill) EditBasePairConnectorFill = false;
            if (EditBasePairConnectorIsFilled) EditBasePairConnectorIsFilled = false;
            if (EditBasePairConnectorIsVisible) EditBasePairConnectorIsVisible = false;
            if (EditBasePairConnectorRenderingStyle) EditBasePairConnectorRenderingStyle = false;
            if (EditBasePairConnectorSize) EditBasePairConnectorSize = false;
            if (EditBasePairConnectorStroke) EditBasePairConnectorStroke = false;
            if (EditBasePairConnectorStrokeThickness) EditBasePairConnectorStrokeThickness = false;
        }

        private void OnPromptForNucleotideFillBrush()
        {
            StructureElementBrushEditorViewModel vm = (NucleotideFill == null) ? new StructureElementBrushEditorViewModel(null) : new StructureElementBrushEditorViewModel(NucleotideFill.ToString());
            IUIVisualizer uiVisualizer = ViewModel.ServiceProvider.Resolve<IUIVisualizer>();
            if (uiVisualizer != null)
            {
                bool? result = uiVisualizer.ShowDialog(typeof(StructureElementBrushEditor).ToString(), vm);
                if (result != null && result.Value)
                {
                    if (vm.ShouldInherit)
                    {
                        NucleotideFill = null;
                    }
                    else
                    {
                        Color requestedColor = (Color)COLOR_CONVERTER.ConvertFrom(vm.Color);
                        NucleotideFill = new SolidColorBrush(requestedColor);
                    }
                }
            }
        }

        private void OnPromptForNucleotideCircleFillBrush()
        {
            StructureElementBrushEditorViewModel vm = (NucleotideCircleFill == null) ? new StructureElementBrushEditorViewModel(null) : new StructureElementBrushEditorViewModel(NucleotideCircleFill.ToString());
            IUIVisualizer uiVisualizer = ViewModel.ServiceProvider.Resolve<IUIVisualizer>();
            if (uiVisualizer != null)
            {
                bool? result = uiVisualizer.ShowDialog(typeof(StructureElementBrushEditor).ToString(), vm);
                if (result != null && result.Value)
                {
                    if (vm.ShouldInherit)
                    {
                        NucleotideCircleFill = null;
                    }
                    else
                    {
                        Color requestedColor = (Color)COLOR_CONVERTER.ConvertFrom(vm.Color);
                        NucleotideCircleFill = new SolidColorBrush(requestedColor);
                    }
                }
            }
        }

        private void OnPromptForNucleotideCircleStrokeBrush()
        {
            StructureElementBrushEditorViewModel vm = (NucleotideCircleStroke == null) ? new StructureElementBrushEditorViewModel(null) : new StructureElementBrushEditorViewModel(NucleotideCircleStroke.ToString());
            IUIVisualizer uiVisualizer = ViewModel.ServiceProvider.Resolve<IUIVisualizer>();
            if (uiVisualizer != null)
            {
                bool? result = uiVisualizer.ShowDialog(typeof(StructureElementBrushEditor).ToString(), vm);
                if (result != null && result.Value)
                {
                    if (vm.ShouldInherit)
                    {
                        NucleotideCircleStroke = null;
                    }
                    else
                    {
                        Color requestedColor = (Color)COLOR_CONVERTER.ConvertFrom(vm.Color);
                        NucleotideCircleStroke = new SolidColorBrush(requestedColor);
                    }
                }
            }
        }

        private void OnPromptForConnectorFillBrush()
        {
            StructureElementBrushEditorViewModel vm = (BasePairConnectorFill == null) ? new StructureElementBrushEditorViewModel(null) : new StructureElementBrushEditorViewModel(BasePairConnectorFill.ToString());
            IUIVisualizer uiVisualizer = ViewModel.ServiceProvider.Resolve<IUIVisualizer>();
            if (uiVisualizer != null)
            {
                bool? result = uiVisualizer.ShowDialog(typeof(StructureElementBrushEditor).ToString(), vm);
                if (result != null && result.Value)
                {
                    if (vm.ShouldInherit)
                    {
                        BasePairConnectorFill = null;
                    }
                    else
                    {
                        Color requestedColor = (Color)COLOR_CONVERTER.ConvertFrom(vm.Color);
                        BasePairConnectorFill = new SolidColorBrush(requestedColor);
                    }
                }
            }
        }

        private void OnPromptForConnectorStrokeBrush()
        {
            StructureElementBrushEditorViewModel vm = (BasePairConnectorStroke == null) ? new StructureElementBrushEditorViewModel(null) : new StructureElementBrushEditorViewModel(BasePairConnectorStroke.ToString());
            IUIVisualizer uiVisualizer = ViewModel.ServiceProvider.Resolve<IUIVisualizer>();
            if (uiVisualizer != null)
            {
                bool? result = uiVisualizer.ShowDialog(typeof(StructureElementBrushEditor).ToString(), vm);
                if (result != null && result.Value)
                {
                    if (vm.ShouldInherit)
                    {
                        BasePairConnectorStroke = null;
                    }
                    else
                    {
                        Color requestedColor = (Color)COLOR_CONVERTER.ConvertFrom(vm.Color);
                        BasePairConnectorStroke = new SolidColorBrush(requestedColor);
                    }
                }
            }
        }

        private void OnAddFilterCondition()
        {
            if (EditingNucleotideProperties)
            {
                BuildBioEntityTypeFilterViewModel vm = new BuildBioEntityTypeFilterViewModel();
                IUIVisualizer uiVisualizer = ViewModel.ServiceProvider.Resolve<IUIVisualizer>();
                if (uiVisualizer != null)
                {
                    bool? result = uiVisualizer.ShowDialog(typeof(BuildNucleotideTypeFilterEditor).ToString(), vm);
                    if (result != null && result.Value)
                    {
                        _ntFilter.Clear();
                        _ntFilter.AddRange(vm.NucleotidesInFilter);
                    }
                }
            }
            else
            {
                BuildBioEntityTypeFilterViewModel vm = new BuildBioEntityTypeFilterViewModel();
                IUIVisualizer uiVisualizer = ViewModel.ServiceProvider.Resolve<IUIVisualizer>();
                if (uiVisualizer != null)
                {
                    bool? result = uiVisualizer.ShowDialog(typeof(BuildBasePairTypeFilterEditor).ToString(), vm);
                    if (result != null && result.Value)
                    {
                        _bpFilter.Clear();
                        _bpFilter.AddRange(vm.BasePairsInFilter);
                    }
                }
            }
        }

        private StructureElementPropertyChangeSet _changes;
        private List<string> _editedGlobalProperties;
        private List<string> _editedTextProperties;
        private List<string> _editedCircleProperties;
        private List<string> _editedBPConnectorProperties;
        private bool _showCreateFilter;
        private List<IBioSymbol> _ntFilter;
        private List<string> _bpFilter; 
        private static ColorConverter COLOR_CONVERTER;

        class EditablePropertyAttribute : Attribute
        {
            public string Category
            {
                get;
                set;
            }

            public EditablePropertyAttribute(string category)
            {
                Category = category;
            }
        }

        class EditablePropertyFlagAttribute : Attribute
        {
            public string EditablePropertyName
            {
                get;
                set;
            }

            public EditablePropertyFlagAttribute(string editablePropertyName)
            {
                EditablePropertyName = editablePropertyName;
            }
        }
    }
}
